package com.maxd.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import com.maxd.adapter.LoginUserHolder;
import com.maxd.bean.PageRes;
import com.maxd.bean.classes.ClassDetail;
import com.maxd.bean.classes.LessonDetail;
import com.maxd.bean.classes.LessonSignReq;
import com.maxd.error.ExceptionEnum;
import com.maxd.model.*;
import com.maxd.respository.*;
import com.maxd.service.partner.IPartnerService;
import com.maxd.utils.AssertUtil;
import com.maxd.utils.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.Predicate;
import java.util.Date;
import java.util.List;

@Service
@Slf4j
public class ClassService {

    @Value("${goods.instructor}")
    private Long instructorGoods;

    @Value("${goods.assistant}")
    private Long assistantGoods;

    @Autowired
    private ClassInfoRepository classInfoRepository;

    @Autowired
    private IPartnerService partnerService;

    @Autowired
    private OrderPartnerInfoRepository orderPartnerInfoRepository;

    @Autowired
    private ClassLessonInfoRepository classLessonInfoRepository;

    @Autowired
    private ClassStudentInfoRepository classStudentInfoRepository;

    @Autowired
    private StudentInfoRepository studentInfoRepository;

    public void save(ClassInfo classInfo) {
        if(classInfo.getInstructorId() != null) {
            OrderPartnerInfo instructor = orderPartnerInfoRepository.findById(classInfo.getInstructorId()).orElse(null);
            AssertUtil.assertTrue(instructor != null && "1".equals(instructor.getStatus()), ExceptionEnum.INSTRUCTOR_NOF);
            classInfo.setInstructorUserId(instructor.getPartnerUserId());
        }
        if(classInfo.getAssistantId() != null) {
            OrderPartnerInfo assistant = orderPartnerInfoRepository.findById(classInfo.getAssistantId()).orElse(null);
            AssertUtil.assertTrue(assistant != null && "1".equals(assistant.getStatus()), ExceptionEnum.ASSISTANT_NOF);
            classInfo.setAssistantUserId(assistant.getPartnerUserId());
        }
        if(classInfo.getId() != null) {
            classInfo.setUpdateTime(new Date());
            classInfo.setUpdateBy(LoginUserHolder.getAdminId());
        } else {
            classInfo.setCreateBy(LoginUserHolder.getAdminId());
            classInfo.setUpdateBy(LoginUserHolder.getAdminId());
        }
        classInfoRepository.save(classInfo);
    }

    public ClassDetail detail(Long id) {
        ClassInfo classInfo = classInfoRepository.findById(id).orElse(null);
        AssertUtil.notNull(classInfo, ExceptionEnum.CLASS_NOF);

        ClassDetail classDetail = new ClassDetail();
        BeanUtils.copyProperties(classInfo, classDetail);

        if(classInfo.getInstructorId() != null) {
            OrderPartnerInfo instructor = orderPartnerInfoRepository.findById(classInfo.getInstructorId()).orElse(null);
            classDetail.setInstructorDetail(instructor);
        }
        if(classInfo.getAssistantId() != null) {
            OrderPartnerInfo assistant = orderPartnerInfoRepository.findById(classInfo.getAssistantId()).orElse(null);
            classDetail.setAssistantDetail(assistant);
        }
        return classDetail;
    }

    public PageRes<ClassInfo> queryPage(Integer pageNo, Integer pageSize, String name, Long instructorUserId) {
        // 分页参数
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        Pageable pageable = PageRequest.of(pageNo, pageSize, sort);
        Specification<ClassInfo> queryCondition = buildCondition(name, instructorUserId);
        Page<ClassInfo> pageList = classInfoRepository.findAll(queryCondition, pageable);
        log.info("分页查询到班级信息为:{}", JsonUtils.toJsonString(pageList));
        return new PageRes<>(pageList.getTotalElements(), pageList.getContent());
    }

    public List<ClassInfo> queryList(String name, Long instructorUserId) {
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        Specification<ClassInfo> queryCondition = buildCondition(name, instructorUserId);
        List<ClassInfo> studentInfos = classInfoRepository.findAll(queryCondition, sort);
        log.info("查询到班级信息为:{}", JsonUtils.toJsonString(studentInfos));
        return studentInfos;
    }

    public void addClassLesson(ClassLessonInfo lessonInfo) {
        Long userId = LoginUserHolder.getUserId();
        AssertUtil.assertTrue(userId != null && userId > 0, ExceptionEnum.WRONT_TOKEN);
        // 查询班级且校验班级教官是否为登录用户
        ClassInfo classInfo = classInfoRepository.findById(lessonInfo.getClassId()).orElse(null);
        AssertUtil.assertTrue(classInfo != null && (userId.equals(classInfo.getInstructorUserId()) || userId.equals(classInfo.getAssistantUserId())), ExceptionEnum.CLASS_NOF);
        lessonInfo.setClassName(classInfo.getName());
        lessonInfo.setInstructorUserId(userId);
        lessonInfo.setAssistantUserId(classInfo.getAssistantUserId());
        //
        if(lessonInfo.getId() != null) {
            lessonInfo.setUpdateTime(new Date());
            lessonInfo.setUpdateBy(String.valueOf(userId));
        } else {
            lessonInfo.setStatus("0");
            lessonInfo.setCreateBy(String.valueOf(userId));
            lessonInfo.setUpdateBy(String.valueOf(userId));
        }
        classLessonInfoRepository.save(lessonInfo);
    }

    public void signLesson(LessonSignReq req) {
        Long userId = LoginUserHolder.getUserId();
        AssertUtil.assertTrue(userId != null && userId > 0, ExceptionEnum.WRONT_TOKEN);

        ClassLessonInfo lessonInfo = classLessonInfoRepository.findById(req.getLessonId()).orElse(null);
        AssertUtil.notNull(lessonInfo, ExceptionEnum.LESSON_NOT_EXISTS);
        AssertUtil.assertTrue(userId.equals(lessonInfo.getInstructorUserId()) || userId.equals(lessonInfo.getAssistantUserId()), ExceptionEnum.PRIVILEGE_ERROR);

        lessonInfo.setStatus("1");
        if(!CollectionUtils.isEmpty(req.getStudentIdList())) {
            lessonInfo.setSignStudents(JsonUtils.toJsonString(req.getStudentIdList()));
        }
        if(!CollectionUtils.isEmpty(req.getImageList())) {
            lessonInfo.setSignImages(JsonUtils.toJsonString(req.getImageList()));
        }
        lessonInfo.setUpdateTime(new Date());
        classLessonInfoRepository.save(lessonInfo);
    }

    public PageRes<ClassLessonInfo> queryClassLessonPage(Integer pageNo, Integer pageSize, Long classId, Long userId, List<Long> classIds) {
        Sort sort = Sort.by(Sort.Direction.DESC, "lessonDate");
        Pageable pageable = PageRequest.of(pageNo, pageSize, sort);
        Specification<ClassLessonInfo> queryCondition = buildCondition(classId, userId, classIds);
        Page<ClassLessonInfo> pageList = classLessonInfoRepository.findAll(queryCondition, pageable);
        log.info("分页查询到班级课程信息为:{}", JsonUtils.toJsonString(pageList));
        return new PageRes<>(pageList.getTotalElements(), pageList.getContent());
    }

    public List<ClassLessonInfo> queryClassLessonList(Long classId, Long instructorUserId, List<Long> classIds) {
        Sort sort = Sort.by(Sort.Direction.DESC, "lessonDate");
        Specification<ClassLessonInfo> queryCondition = buildCondition(classId, instructorUserId, classIds);
        List<ClassLessonInfo> recordList = classLessonInfoRepository.findAll(queryCondition, sort);
        log.info("查询到班级课程信息为:{}", JsonUtils.toJsonString(recordList));
        return recordList;
    }

    public LessonDetail queryClassLessonDetail(Long lessonId, Long userId) {
        ClassLessonInfo lessonInfo = classLessonInfoRepository.findById(lessonId).orElse(null);
        AssertUtil.notNull(lessonInfo, ExceptionEnum.LESSON_NOT_EXISTS);
        if(userId != null) {
            AssertUtil.assertTrue(userId.equals(lessonInfo.getInstructorUserId()) || userId.equals(lessonInfo.getAssistantUserId()), ExceptionEnum.PRIVILEGE_ERROR);
        }
        LessonDetail lessonDetail = new LessonDetail();
        BeanUtils.copyProperties(lessonInfo, lessonDetail);

        ClassDetail classDetail = detail(lessonDetail.getClassId());
        lessonDetail.setClassDetail(classDetail);

        if(StringUtils.isNotEmpty(lessonInfo.getSignStudents())) {
            List<Long> studentIds = JsonUtils.parseObject(lessonInfo.getSignStudents(), new TypeReference<List<Long>>() {});
            List<StudentInfo> classStudents = studentInfoRepository.findAllById(studentIds);
            lessonDetail.setSignStudentList(classStudents);
        }

        if(StringUtils.isNotEmpty(lessonInfo.getSignImages())) {
            List<String> imageList = JsonUtils.parseObject(lessonInfo.getSignImages(), new TypeReference<List<String>>() {});
            lessonDetail.setSignImageList(imageList);
        }
        return lessonDetail;
    }

    private Specification<ClassInfo> buildCondition(String name, Long userId) {

        log.info("查询班级信息，查询条件: name = {}, userId = {}", name, userId);

        Specification<ClassInfo> queryCondition = (root, query, criteriaBuilder) -> {
            List<Predicate> rootPredicate = Lists.newArrayList();

            if(StringUtils.isNotEmpty(name)) {
                rootPredicate.add(criteriaBuilder.like(root.get("name"), "%" + name + "%"));
            }

            if(userId != null) {
                Predicate or = criteriaBuilder.or(criteriaBuilder.equal(root.get("instructorUserId"), userId), criteriaBuilder.equal(root.get("assistantUserId"), userId));
                rootPredicate.add(or);
            }
            return criteriaBuilder.and(rootPredicate.toArray(new Predicate[rootPredicate.size()]));
        };
        return queryCondition;
    }

    private Specification<ClassLessonInfo> buildCondition(Long classId, Long userId, List<Long> classIds) {
        Specification<ClassLessonInfo> queryCondition = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();

            if(classId != null) {
                predicates.add(criteriaBuilder.equal(root.get("classId"), classId));
            }
            if(!CollectionUtils.isEmpty(classIds)) {
                predicates.add(criteriaBuilder.in(root.get("classId")).value(classIds));
            }

            if(userId != null) {
                Predicate predicateOr = criteriaBuilder.or(criteriaBuilder.equal(root.get("instructorUserId"), userId), criteriaBuilder.equal(root.get("assistantUserId"), userId));
                predicates.add(predicateOr);
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        return queryCondition;
    }
}
